package cn.harry.common.utils;

import cn.hutool.core.date.DateUtil;
import com.google.gson.Gson;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * Redis工具类
 *
 * @author honghh Date 2019/07/18 14:03 Copyright (C) www.honghh.top
 */
public class RedisUtils {

	private static final RedisTemplate<String, Object> redisTemplate = SpringUtils
			.getBean("redisTemplate");

	private static final ValueOperations<String, String> valueOperations = SpringUtils
			.getBean("valueOperations");

	private static final StringRedisTemplate stringRedisTemplate = SpringUtils
			.getBean("stringRedisTemplate");

	/**
	 * 不设置过期时长
	 */
	private final static long NOT_EXPIRE = -1;

	/**
	 * 默认编码
	 */
	private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;

	private final static Gson GSON = new Gson();

	public static void set(String key, Object value, long expire) {
		valueOperations.set(key, toJson(value));
		if (expire != NOT_EXPIRE) {
			redisTemplate.expire(key, expire, TimeUnit.SECONDS);
		}
	}

	public static void set(String key, Object value) {
		set(key, value, NOT_EXPIRE);
	}

	public static <T> T get(String key, Class<T> clazz, long expire) {
		String value = valueOperations.get(key);
		if (expire != NOT_EXPIRE) {
			redisTemplate.expire(key, expire, TimeUnit.SECONDS);
		}
		return value == null ? null : fromJson(value, clazz);
	}

	public static <T> T get(String key, Class<T> clazz) {
		return get(key, clazz, NOT_EXPIRE);
	}

	public static String get(String key, long expire) {
		String value = valueOperations.get(key);
		if (expire != NOT_EXPIRE) {
			redisTemplate.expire(key, expire, TimeUnit.SECONDS);
		}
		return value;
	}

	public static String get(String key) {
		return get(key, NOT_EXPIRE);
	}

	public static void delete(String key) {
		redisTemplate.delete(key);
	}

	/**
	 * Object转成JSON数据
	 */
	private static String toJson(Object object) {
		if (object instanceof Integer || object instanceof Long || object instanceof Float
				|| object instanceof Double || object instanceof Boolean
				|| object instanceof String) {
			return String.valueOf(object);
		}
		return GSON.toJson(object);
	}

	/**
	 * JSON数据，转成Object
	 */
	private static <T> T fromJson(String json, Class<T> clazz) {
		return GSON.fromJson(json, clazz);
	}

	public boolean exists(final String key) {
		return stringRedisTemplate
				.execute((RedisCallback<Boolean>) connection -> connection
						.exists(key.getBytes(DEFAULT_CHARSET)));
	}

	/**
	 * 自增操作
	 * @param delta 自增步长
	 */
	public static Long increment(String key, long delta) {
		return stringRedisTemplate.opsForValue().increment(key, delta);
	}

	/**
	 * 自增操作
	 */
	public Long increment(String prefix, String key) {
		Long i = stringRedisTemplate.opsForValue().increment(prefix + key);
		if (i != null && i == 1L) {
			String key2 = new SimpleDateFormat("yyyyMMdd").format(DateUtil.yesterday());
			System.out.println("key2:  " + key2);
			delete(prefix + key2);
		}
		return i;
	}

	/**
	 * 查找匹配key
	 * @param pattern key
	 * @return /
	 */
	public static List<String> scan(String pattern) {
		ScanOptions options = ScanOptions.scanOptions().match(pattern).build();
		RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
		RedisConnection rc = Objects.requireNonNull(factory).getConnection();
		Cursor<byte[]> cursor = rc.scan(options);
		List<String> result = new ArrayList<>();
		while (cursor.hasNext()) {
			result.add(new String(cursor.next()));
		}
		try {
			RedisConnectionUtils.releaseConnection(rc, factory);
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

}
